/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.view;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Walter L�tgenau
 */
public class UserAgentDetector {
    public static final String OS = "OS_";
    public static final String UA = "UA_";
    public static final String REQUEST_HEADER = "User-Agent";
    public static final String SEPARATOR_VERSION = ":";
    public static final String SEPARATOR_GROUP = ",";

    private static final String PROPERTIES_FILE = "UserAgent.properties";

    private static HashMap<String, String> userAgents = new HashMap<String, String>();
    private static HashMap<String, String> operatingSystems = new HashMap<String, String>();
    private static Pattern type = Pattern.compile("[a-z]*");
    private static Pattern version = Pattern.compile("[0-9]*");
    private static Logger logger = LoggerFactory.getLogger(UserAgentDetector.class);

    String userAgent = "unknown0";
    String userAgentType = "unknown";
    String userAgentVersion = "0";
    String operatingSystem = "unknown0";
    String operatingSystemType = "unknown";
    String operatingSystemVersion = "0";

    static {
        // initialize the user agent knowledge from the properties file.
        try {
            Properties properties = new Properties();
            properties.load(UserAgentDetector.class.getResourceAsStream(PROPERTIES_FILE));

            Enumeration<String> keys = (Enumeration<String>) properties.propertyNames();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement();

                if (key.startsWith(UA))
                    userAgents.put(properties.getProperty(key), key.substring(UA.length()));
                else
                    operatingSystems.put(properties.getProperty(key), key.substring(OS.length()));
            }
        } catch (IOException e) {
            logger.warn("Could not obtain " + PROPERTIES_FILE);
        }
    }

    /**
     * Return an instance of the user agent detector. Create and initialize it, if necessary.
     * Add the user agent detector to the session, it will serve as a user agent settings
     * cache.
     *
     * @param request the request
     * @return the user agent detector
     */
    public static synchronized UserAgentDetector getInstance(HttpServletRequest request) {
        UserAgentDetector instance = new UserAgentDetector();
        instance.init(request);

        return instance;
    }

    /**
     * Initialize the user agent detector from the static user agent knowledge
     * and the current request.
     *
     * @param request the current request
     */
    private void init(HttpServletRequest request) {
        String userAgentHeader = request.getHeader(REQUEST_HEADER);
        if (userAgentHeader == null)
            return;

        String keyFound = null;
        for (String key : userAgents.keySet()) {
            if (keyFound != null && !key.startsWith(keyFound)) // found and not a more specific member of the family
                continue;
            
            if (key.indexOf(SEPARATOR_GROUP) >= 0) {
                String[] members = key.split(SEPARATOR_GROUP);
                for (String member : members) {
                    if (userAgentHeader.indexOf(member) >= 0) {
                        setUserAgent(key);
                        break;
                    }
                }
            } else {
                String version = null;

                if (key.indexOf(SEPARATOR_VERSION) >= 0) {
                    version = key.substring(key.indexOf(SEPARATOR_VERSION) + 1);
                    key = key.substring(0, key.indexOf(SEPARATOR_VERSION));
                }

                if (userAgentHeader.indexOf(key) >= 0) {
                    if (version != null && userAgentHeader.indexOf(version) < 0)
                        continue;

                    setUserAgent(userAgents.get(key));
                    keyFound = key;
                }
            }
        }

        for (String key : operatingSystems.keySet()) {
            if (userAgentHeader.indexOf(key) >= 0) {
                setOperatingSystem(operatingSystems.get(key));
                break;
            }
        }

        Matcher matcher = type.matcher(getUserAgent());
        if (matcher.find())
            userAgentType = matcher.group();

        matcher = version.matcher(getUserAgent());
        if (matcher.find())
            userAgentVersion = matcher.group();

        matcher = type.matcher(getOperatingSystem());
        if (matcher.find())
            operatingSystemType = matcher.group();

        matcher = version.matcher(getOperatingSystem());
        if (matcher.find())
            operatingSystemVersion = matcher.group();
    }

    public String getOperatingSystem() {
        return operatingSystem;
    }

    protected void setOperatingSystem(String operatingSystem) {
        this.operatingSystem = operatingSystem;
    }

    public String getUserAgent() {
        return userAgent;
    }

    protected void setUserAgent(String userAgent) {
        this.userAgent = userAgent;
    }

    public String getOperatingSystemType() {
        return operatingSystemType;
    }

    public String getOperatingSystemVersion() {
        return operatingSystemVersion;
    }

    public String getUserAgentType() {
        return userAgentType;
    }

    public String getUserAgentVersion() {
        return userAgentVersion;
    }

}
